//SpiralSprite class by Jason Milliser

using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;

namespace SCG.TurboSprite
{
    public class SpiralSprite : Sprite
    {
        //constructor
        public SpiralSprite(int arms, float radiusmin, int radiusmax, int armslope, int slopelength, bool isSpinningClockwise, int spinrate, Color EdgeColor, Color CenterColor)
        {
            //arm slope is the number of lines drawn to the center of the spiral. Also controls the tightness of teh spiral.
            //spinrate determines how many degrees the spiral spins in one frame. 
            //slopelength is the length of each line segment of each spiral. longer lines can tighten spiral, but quality will go down.
            slength = slopelength;
            scentercolor = CenterColor;
            sedgecolor = EdgeColor;
            sdirection = isSpinningClockwise;
            sspinrate = spinrate;
            sradiusmax = radiusmax;
            sradiusmin = radiusmin;
            sarmslope = armslope;
            sarms = arms;
            Shape = new RectangleF(0-sradiusmax, 0-sradiusmax, sradiusmax * 2, sradiusmax * 2);
        }

        public override void Process()
        {
            int theta = 0;
            float sinvalue = 0;
            float cosvalue = 0;
            double altitude = 0;
            float faltitude = 0;
            double radiusscale = 0;
            double dradiusmin = 0;
            int rdegrees = 0;

            //rotate spiral
            if (sdirection == false) degreesrotated = degreesrotated + sspinrate;
            else degreesrotated = degreesrotated - sspinrate;
            while (degreesrotated < 0) degreesrotated = degreesrotated + 360;
            while (degreesrotated >= 360) degreesrotated = degreesrotated - 360;

            //preliminary math calculations
            theta = 360 / sarms;

            _points = new PointF[sarms * sarmslope + 1];

            for (int arm = 0; arm < sarms; arm++)
            {
                for (int seg = 0; seg < sarmslope; seg++)
                {
                    if (sdirection == true)
                        rdegrees = degreesrotated + (seg * slength) + (arm * theta);
                    else
                        rdegrees = degreesrotated - (seg * slength) - (arm * theta);
                    while (rdegrees < 0) rdegrees = rdegrees + 360;
                    while (rdegrees >= 360) rdegrees = rdegrees - 360;

                    radiusscale = sradiusmax - sradiusmin;
                    dradiusmin = sarmslope;
                    altitude = (seg + 1) / dradiusmin;
                    altitude = radiusscale * altitude;
                    dradiusmin = sradiusmin;
                    altitude = dradiusmin + altitude;
                    faltitude = Convert.ToSingle(altitude);

                    sinvalue = Sin(rdegrees) * faltitude;
                    cosvalue = Cos(rdegrees) * faltitude;

                    _points[(arm * sarmslope) + seg].X = sinvalue;
                    _points[(arm * sarmslope) + seg].Y = cosvalue;
                }
            }
        }

        //Render the sprite
        public override void Render(System.Drawing.Graphics g)
        {
            Pen pen = new Pen(Color.White);
            int cpoint = 0;
            float currx = 0;
            float curry = 0;
            float lastx = -32767;
            float lasty = -32767;

            for (int dpoint = 0; dpoint < _points.Length; dpoint++)
            {
                currx = X - Surface.OffsetX;
                curry = Y - Surface.OffsetY;
                currx = _points[dpoint].X + currx;
                curry = _points[dpoint].Y + curry;
                if ((lastx > -32767) & (lasty > -32767))
                {
                    pen.Color = ColorScale(sedgecolor, scentercolor,sarmslope,sarmslope - cpoint);
                    g.DrawLine(pen, currx, curry, lastx, lasty);
                }
                if (cpoint < sarmslope - 1)
                {
                    lastx = currx;
                    lasty = curry;
                    cpoint = cpoint + 1;
                }
                else
                {
                    cpoint = 0;
                    lastx = -32767;
                    lasty = -32767;
                }
            }
        }

        //Obtain a color between two selected colors.
        private static Color ColorScale(Color startColor, Color endColor, int numPoints, int sPoint)
        {
            //determine color transistion rate
            int bluediff = startColor.B - endColor.B;
            int greendiff = startColor.G - endColor.G;
            int reddiff = startColor.R - endColor.R;
            int alphadiff = startColor.A - endColor.A;

            int rred = (reddiff / numPoints) * sPoint;
            int rgreen = (greendiff / numPoints) * sPoint;
            int rblue = (bluediff / numPoints) * sPoint;
            int ralpha = (alphadiff / numPoints) * sPoint;

            rred = startColor.R - rred;
            rgreen = startColor.G - rgreen;
            rblue = startColor.B - rblue;
            ralpha = startColor.A - ralpha;

            return Color.FromArgb(ralpha, rred,rgreen,rblue);
        }


        //private members
        private PointF[] _points;
        private int sarms;
        private float sradiusmax;
        private float sradiusmin;
        private int sarmslope;
        private Color scentercolor;
        private Color sedgecolor;
        private int degreesrotated = 0;
        private int sspinrate;
        private bool sdirection;
        private int slength;
    }
}
